package com.memory.licenseserver.license;

import com.memory.common.bean.LicenseCheckModel;
import com.memory.common.bean.LicenseCreatorParam;
import com.memory.common.license.*;
import de.schlichtherle.license.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestParam;

import javax.security.auth.x500.X500Principal;
import java.io.*;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.prefs.Preferences;

/**
 * License生成类
 */
public class LicenseCreator {
    public static Logger log = LoggerFactory.getLogger(LicenseCreator.class);

    // X500Princal 是一个证书文件的固有格式，详见API
    private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = new X500Principal("CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN");
    private LicenseCreatorParam param;

    /**
     * 证书 subject
     */
    @Value("${license.subject}")
    private String subject;

    /**
     * 密钥别称
     */
    @Value("${license.private-alias}")
    private String privateAlias;

    /**
     * 密钥密码
     */
    @Value("${license.key-pass}")
    private String keyPass;

    /**
     * 访问密钥库的密码
     */
    @Value("${license.store-pass}")
    private String storePass;

    /**
     * 证书生成路径
     */
    @Value("${license.license-path}")
    private String licensePath;

    /**
     * 密钥库存储路径
     */
    @Value("${license.private-keys-store-path}")
    private String privateKeysStorePath;

    /**
     * 证书有效期开始时间
     */
    @Value("${license.issued-time}")
    private String issuedTime;

    /**
     * 证书有效期结束时间
     */
    @Value("${license.expiry-time}")
    private String expiryTime;

    /**
     * 用户类型
     */
    @Value("${license.consumer-type}")
    private String consumerType;

    /**
     * 证书可使用的用户数量
     */
    @Value("${license.consumer-amount}")
    private int consumerAmount;

    /**
     * 证书描述信息
     */
    @Value("${license.description}")
    private String description;

    public LicenseCreator() {
    }


    public LicenseCreator(LicenseCreatorParam param) {
        this.param = param;
    }

    /**
     * 生成License证书
     *
     * @return boolean
     */
    public boolean generateLicense() {
        try {
            param = new LicenseCreatorParam();
            // 设置证书生成参数
            this.setParam(param);
            LicenseManager licenseManager = new CustomLicenseManager(initLicenseParam());
            LicenseContent licenseContent = initLicenseContent();

            licenseManager.store(licenseContent, new File(param.getLicensePath()));
            log.info("证书生成成功");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error(MessageFormat.format("证书生成失败：{0}", param), e.getMessage());
            return false;
        }
    }

    /**
     * 生成License证书
     *
     * @return boolean
     */
    public boolean generateLicense2() {
        try {
            LicenseManager licenseManager = new CustomLicenseManager(initLicenseParam());
            LicenseContent licenseContent = initLicenseContent();

            licenseManager.store(licenseContent, new File(param.getLicensePath()));
            log.info("证书生成成功");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error(MessageFormat.format("证书生成失败：{0}", param), e.getMessage());
            return false;
        }
    }

    /**
     * 设置证书生成参数
     *
     * @param param
     */
    public void setParam(LicenseCreatorParam param) {
        Properties prop = new Properties();
        try {
            prop.load(LicenseCreator.class.getResourceAsStream("/application.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        param.setSubject(prop.getProperty("license.subject"));
        param.setPrivateAlias(prop.getProperty("license.private-alias"));
        param.setKeyPass(prop.getProperty("license.key-pass"));
        param.setStorePass(prop.getProperty("license.store-pass"));
        param.setLicensePath(prop.getProperty("license.license-path"));
        param.setPrivateKeysStorePath(System.getProperty("user.dir") + prop.getProperty("license.private-keys-store-path"));
        param.setIssuedTime(new Date());

        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            param.setExpiryTime(sdf.parse(prop.getProperty("license.expiry-time")));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        param.setConsumerType(prop.getProperty("license.consumer-type"));
        param.setConsumerAmount(Integer.parseInt(prop.getProperty("license.consumer-amount")));
        param.setDescription(prop.getProperty("license.description"));

        // 扩展校验服务器硬件信息
        String osName = System.getProperty("os.name");
        LicenseCheckModel serverInfos = this.getServerInfos(osName);
        param.setLicenseCheckModel(serverInfos);
    }

    /**
     * 扩展校验服务器硬件信息
     *
     * @param osName
     * @return
     */
    private LicenseCheckModel getServerInfos(String osName) {
        // 操作系统类型
        if (StringUtils.isBlank(osName)) {
        }
        osName = osName.toLowerCase();
        AbstractServerInfos abstractServerInfos = null;

        // 根据不同操作系统类型选择不同的数据获取方法
        if (osName.startsWith("windows")) {
            abstractServerInfos = new WindowsServerInfos();
        } else if (osName.startsWith("linux")) {
            abstractServerInfos = new LinuxServerInfos();
        } else {// 其他服务器类型
            abstractServerInfos = new LinuxServerInfos();
        }

        return abstractServerInfos.getServerInfos();
    }



    /**
     * 初始化证书生成参数
     *
     * @return de.schlichtherle.license.LicenseParam
     */
    private LicenseParam initLicenseParam() {
        Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class);

        // 设置对证书内容加密的秘钥
        CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());

        KeyStoreParam privateStoreParam = new CustomKeyStoreParam(LicenseCreator.class
                , param.getPrivateKeysStorePath()
                , param.getPrivateAlias()
                , param.getStorePass()
                , param.getKeyPass());

        LicenseParam licenseParam = new DefaultLicenseParam(param.getSubject()
                , preferences
                , privateStoreParam
                , cipherParam);

        return licenseParam;
    }

    /**
     * 设置证书生成正文信息
     *
     * @return de.schlichtherle.license.LicenseContent
     */
    private LicenseContent initLicenseContent() {
        LicenseContent licenseContent = new LicenseContent();
        licenseContent.setHolder(DEFAULT_HOLDER_AND_ISSUER);
        licenseContent.setIssuer(DEFAULT_HOLDER_AND_ISSUER);

        licenseContent.setSubject(param.getSubject());
        licenseContent.setIssued(param.getIssuedTime());
        licenseContent.setNotBefore(param.getIssuedTime());
        licenseContent.setNotAfter(param.getExpiryTime());
        licenseContent.setConsumerType(param.getConsumerType());
        licenseContent.setConsumerAmount(param.getConsumerAmount());
        licenseContent.setInfo(param.getDescription());

        // 扩展校验服务器硬件信息
        licenseContent.setExtra(param.getLicenseCheckModel());

        return licenseContent;
    }

}
